﻿using TrackSystem.IO.Data;
using TrackSystem.IO.Models;

namespace TrackSystem.IO.Protocol
{
    /// <summary>
    /// 绝缘检测  采用不请求的MODBUS协议，直接向上发0,1寄存器的数据
    /// </summary>
    public class InsulatProtocol : ProtocolBase
    {
        private readonly int roAddr;
        private readonly int roLength;
        private readonly int rwAddr;
        private readonly int rwLength;
        private bool bSendR;
        private int startTicks;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="name">只读存储器起始地址</param>
        /// <param name="station">站地址</param>
        public InsulatProtocol(string name,int station)
            : base()
        {
            Name = name;
            this.Station = station;
            this.roAddr = 0;
            this.roLength = 2;

            bSendR = false;
        }

        /// <summary>
        /// 生成读取寄存器的通讯帧
        /// </summary>
        /// <returns></returns>
        public override byte[] GenerateReadFrame(out int NeedRecvLen)
        {
            // 上次的发送没有收到正确回复，bSend没有被置位
            startTicks = Environment.TickCount;

            // 上次的发送没有收到正确回复，bSend没有被置位
            if (bSendR)
            {
                Fail_R++;
                // 失败超过10次，成功次数清零
                if (Fail_R >= 10)
                {
                    Succ_R = 0;
                }
            }
            bSendR = true;

            // 访问只读存储器  该协议发回Modbus的两个数据
            NeedRecvLen = 2 * roLength + 5;
            return null;
        }

        /// <summary>
        /// 根据收到的内容进行处理
        /// </summary>
        /// <returns></returns>
        public override bool ProcessReadFrame(byte[] buffer)
        {
            Lapse = Environment.TickCount - startTicks;

            //保存返回的数据
            int nLen = buffer.Length;
            Rx_r = buffer;

            // 站号不对
            if (buffer[0] != Station)
                return false;

            // 功能码不对
            if (buffer[1] != 0x03)
                return false;

            // 数据帧长度不对
            if (buffer[2] > (nLen - 5))
                //if (buffer[2] != (nLen - 5))
                return false;

            // CRC不正确
            int realLen = buffer[2] + 5;  // 实际帧长度
            ushort crc = CRC16(buffer, realLen - 2);
            if (crc != (buffer[realLen - 2] | (buffer[realLen - 1] << 8)))
                return false;

            int Index = 0;

            for (int i = 3; i < (realLen - 2); i += 2)
            {
                RegFactory.Instance.SetVal(RegNameList[Index++], buffer[i] << 8 | buffer[i + 1]);
            }

            Succ_R++;
            bSendR = false;     // 正确收到，标志位变为false
            Fail_R = 0;         // 通信成功，则将失败次数清零

            return true;
        }

        /// <summary>
        /// 改变变量的值
        /// </summary>
        /// <param name="Index"></param>
        /// <param name="Value"></param>
        public override void PushRegValue(int Index, double Value)
        {
            Index -= roLength;  //寄存器存储顺序从0开始，先是只读存储器，后面是读写存储器

            if (Index >= 0 && (Index < rwLength))
            {
                writeQueue.Enqueue(new AddressAndVal(Index, Value));
                WriteFlag = true;
            }
        }

        /// <summary>
        /// CRC校验
        /// </summary>
        /// <param name="pDataBytes"></param>
        /// <param name="nLen"></param>
        /// <returns></returns>
        public static ushort CRC16(byte[] pDataBytes, int nLen)
        {
            ushort crc = 0xFFFF;
            ushort polynom = 0xA001;

            for (int i = 0; i < nLen; i++)
            {
                crc ^= pDataBytes[i];
                for (int j = 0; j < 8; j++)
                {
                    if ((crc & 0x01) == 0x01)
                    {
                        crc >>= 1;
                        crc ^= polynom;
                    }
                    else
                        crc >>= 1;
                }
            }
            return crc;
        }
    }
}
